package org.joinme.backend.util;
	
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.cache.CacheConfig;
import org.apache.http.impl.client.cache.CachingHttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class ApiHttp {
	public enum METHOD {
		DELETE, GET, POST, PUT;
	}
	
	private static CloseableHttpClient mHttpClient;
	
	private static final String DEFAULT_UA = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36";

	static {
		PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
		cm.setMaxTotal(200);
		cm.setDefaultMaxPerRoute(20);
		RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(10000).setConnectTimeout(10000)
				.setSocketTimeout(10000).build();
		SocketConfig socketConfig = SocketConfig.custom().setSoKeepAlive(true).build();
		CacheConfig cacheConfig = CacheConfig.custom().setMaxCacheEntries(1000).setMaxObjectSize(8192).build();
		HttpClientBuilder builder = CachingHttpClients.custom().setCacheConfig(cacheConfig)
				.setRetryHandler(new HttpRequestRetryHandler() {
					public boolean retryRequest(IOException arg0, int executionCount, HttpContext arg2) {
						return executionCount < 3;
					}
				}).setConnectionManager(cm).setDefaultSocketConfig(socketConfig).setDefaultRequestConfig(config)
				.setUserAgent(DEFAULT_UA);
		mHttpClient = builder.build();
//		mHttpClient = HttpClientBuilder.create().build();
	}
	
	public static String doGet(String url){
		try {
			URL urlEntity = new URL(url);
			URI uri = new URI(urlEntity.getProtocol(), urlEntity.getHost(), urlEntity.getPath(), urlEntity.getQuery(), null);
			
			HttpGet get = new HttpGet(uri);
			
			CloseableHttpResponse response = null;
			try {
				response = mHttpClient.execute(get);
			} catch (Exception e) {
				e.printStackTrace();
				return "";
			}
			
			HttpEntity entity = null;
			try {
				entity = response.getEntity();
				String ret = entity != null ? EntityUtils.toString(entity, "utf-8") : null;
				
				return ret;
			} finally {
				if (response != null) {
					response.close();
				}
				try {
					EntityUtils.consume(entity);
				} catch (Exception e) {

				}
			}
		}
		catch (Exception e){
			e.printStackTrace();
		}
		return "";
	}
	
	public static String doGet(String url , JSONObject input){
		try {
			HttpGet get = new HttpGet(buildUrl(url, input));
			
			CloseableHttpResponse response = null;
			try {
				response = mHttpClient.execute(get);
			} catch (Exception e) {
				//e.printStackTrace();
				return "";
			}
			
			HttpEntity entity = null;
			try {
				entity = response.getEntity();
				String ret = entity != null ? EntityUtils.toString(entity, "utf-8") : null;
				
				return ret;
			} finally {
				if (response != null) {
					response.close();
				}
				try {
					EntityUtils.consume(entity);
				} catch (Exception e) {

				}
			}
		}
		catch (Exception e){
			e.printStackTrace();
		}
		return "";
	}
	
	public static String doPost(String url, String content, Map<String, String> headers) {
		try {
			return executeReturnString(prepareUriRequest(METHOD.POST, url, headers, content));
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

	}
	
	public static String doPost(String url, Map<String, String> params, Map<String, String> headers) {
		try {
			return executeReturnString(prepareUriRequest(METHOD.POST, url, headers, params));
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

	}

	public static JSONObject doPostJsonData(String url, JSONObject input) {
		try {
			return executeReturnJson(prepareUriRequest(METHOD.POST, url, null, input));
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public static JSONObject doPostJsonData(String url, JSONObject input, Map<String, String> headers) {
		try {
			return executeReturnJson(prepareUriRequest(METHOD.POST, url, headers, input));
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public static JSONObject executeReturnJson(HttpUriRequest request) throws HttpException, IOException {
		String ret = executeReturnString(request);
		if (null == ret) {
			throw new IOException("empty response");
		}

		return JSON.parseObject(ret);
	}
	
	public static String executeReturnString(HttpUriRequest request) throws HttpException, IOException {
		if (null == request) {
			throw new IOException("empty request");
		}

		// Prepare header
		CloseableHttpClient httpclient = mHttpClient;

		// Execute HTTP request
		CloseableHttpResponse response1 = null;
		try {
			response1 = httpclient.execute(request);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		HttpEntity entity1 = null;
		try {
			entity1 = response1.getEntity();
			String ret = entity1 != null ? EntityUtils.toString(entity1, "UTF-8") : null;

			return ret;
		} finally {
			if (response1 != null) {
				response1.close();
			}
			try {
				EntityUtils.consume(entity1);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static HttpUriRequest prepareUriRequest(METHOD method, String url, Map<String, String> headers,
                                                   JSONObject data) throws IOException {
		String content = null;

		if (null != data) {
			content = data.toJSONString();
			if (null == headers) {
				headers = new HashMap<String, String>();
			}
			headers.put("content-type", "application/json");
		}
		return prepareUriRequest(method, url, headers, content);
	}
	
	public static HttpUriRequest prepareUriRequest(METHOD method, String url, Map<String, String> headers,
                                                   String content) throws IOException {
		HttpEntity entity = null;
		if (null != content) {
			entity = new StringEntity(content, "UTF-8");
		}
		return prepareUriRequest(method, url, headers, entity);
	}
	
	public static HttpUriRequest prepareUriRequest(METHOD method, String url, Map<String, String> headers,
                                                   HttpEntity entity) throws IOException {

		HttpUriRequest request = null;
		HttpEntityEnclosingRequestBase requestWithEntity = null;
		switch (method) {
		case GET:
			request = new HttpGet(url);
			break;
		case POST:
			requestWithEntity = new HttpPost(url);
			break;
		case PUT:
			requestWithEntity = new HttpPut(url);
			break;
		case DELETE:
			request = new HttpDelete(url);
			break;
		default:
			throw new IOException("unexpected method " + method);
		}
		if (null != requestWithEntity && null != entity) {
			requestWithEntity.setEntity(entity);
			request = requestWithEntity;
		}

		if (null != headers) {
			for (String key : headers.keySet()) {
				request.addHeader(key, headers.get(key));
			}
		}

		return request;
	}
	
	public static HttpUriRequest prepareUriRequest(METHOD method, String url, Map<String, String> headers,
                                                   Map<String, String> params) throws IOException, URISyntaxException {
		HttpEntity entity = null;
		if (null != params) {
			switch (method) {
			case PUT:
			case POST:
				List<NameValuePair> nvps = new ArrayList<NameValuePair>();
				for (String k : params.keySet()) {
					nvps.add(new BasicNameValuePair(k, params.get(k)));
				}
				entity = new UrlEncodedFormEntity(nvps, "UTF-8");
				break;
			case DELETE:
			case GET:
				url = buildUrl(url, params);
				break;
			}
		}
		return prepareUriRequest(method, url, headers, entity);
	}
	
	private static String buildUrl(String url, JSONObject input){
		if(input == null)
			return url;
		
		StringBuilder sb = new StringBuilder();
		for(Entry<String, Object> entry: input.entrySet()){
			sb = sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
		}

		if(sb.length() > 0){
			sb = sb.deleteCharAt(sb.length()-1);
			
			System.out.println(">>>>> " + url + "?" + sb);
			return url + "?" + sb;
		}
		
		return url;
	}

	private static String buildUrl(String urlBase, Map<String, String> input) {
		try {
			if (null == input) {
				return null;
			}

			URIBuilder builder = new URIBuilder(urlBase);
			for (String key : input.keySet()) {
				builder.addParameter(key, input.get(key));
			}
			String url = builder.build().toString();
			return url;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}
